﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;

using DapperExtensions;
namespace Agile.Service.Flow
{
    ///<summary>
    ///工作流流程实例表
    ///</summary>
    public interface IFlowInstanceService : IRepository<FlowInstance>
    {
        JQridPageData FindAll(QueryFlowInstanceListReq request);
        /// <summary>
        /// 历史流程
        /// </summary>
        /// <param name="flowInstanceId"></param>
        /// <returns></returns>
        List<FlowInstanceOperationHistory> QueryHistories(string flowInstanceId);
        /// <summary>
        /// 审核流程
        /// </summary>
        void Verification(VerificationReq request);

        /// <summary>
        /// 创建一个实例
        /// </summary>
        bool CreateInstance(AddFlowInstanceReq addFlowInstanceReq);
        /// <summary>
        /// 驳回
        /// </summary>
        bool NodeReject(VerificationReq reqest);
        /// <summary>
        /// 节点审核
        /// </summary>
        bool NodeVerification(string instanceId, Tag tag);
    }
    ///<summary>
    ///工作流流程实例表
    ///</summary>
    public partial class FlowInstanceService : BaseRepository<FlowInstance>, IFlowInstanceService
    {
        private readonly IFlowSchemeService flowSchemeDal;
        //private readonly IFormService formDal;
        private readonly IFlowInstanceTransitionHistoryService flowInstanceTransitionHistoryDal;
        private readonly IFlowInstanceOperationHistoryService flowInstanceOperationHistoryDal;

        private readonly IRelevanceService relevanceDal;
        private readonly ILoginInfo loginInfoDal;

        public FlowInstanceService(
            IFlowSchemeService flowSchemeRepository,
            //IFormService formRepository,
            IFlowInstanceTransitionHistoryService flowInstanceTransitionHistoryRepository,
            IFlowInstanceOperationHistoryService flowInstanceOperationHistoryRepository,
            IRelevanceService relevanceService,
            ILoginInfo loginInfoService
            )
        {
            flowSchemeDal = flowSchemeRepository;
            //formDal = formRepository;
            flowInstanceTransitionHistoryDal = flowInstanceTransitionHistoryRepository;
            flowInstanceOperationHistoryDal = flowInstanceOperationHistoryRepository;
            relevanceDal = relevanceService;
            loginInfoDal = loginInfoService;
        }

        public JQridPageData FindAll(QueryFlowInstanceListReq request)
        {
            string sqlwhere = "";
            JQridPageData pageData = new JQridPageData();
            if (request.type == "wait")
            {
                //待办事项
                sqlwhere = "MakerList='1' or MakerList='" + request.userid + "' ";
            }
            else if (request.type == "disposed")
            {
                //已办事项（即我参与过的流程）
                sqlwhere = "ID in(select InstanceId from [flow_flowInstanceTransitionHistory] where [CreateUserId]='" + request.userid + "') ";
            }
            else
            {
                //我的流程
                sqlwhere = "CreateUserId='" + request.userid + "' ";
            }
            var data = FindAll(sqlwhere, "OrderBy desc", request.page, request.rows);
            pageData.rows = data;
            pageData.page = request.page;
            pageData.records = FindAll(sqlwhere).Count();
            return pageData;
        }
        public List<FlowInstanceOperationHistory> QueryHistories(string flowInstanceId)
        {
            return flowInstanceOperationHistoryDal.FindAll("InstanceId='" + flowInstanceId + "'").ToList();
        }
        /// <summary>
        /// 审核流程
        /// </summary>
        public void Verification(VerificationReq request)
        {
            var tag = new Tag
            {
                UserName = request.UserId,
                UserId = request.UserName,
                Description = request.VerificationOpinion,
                Taged = Int32.Parse(request.VerificationFinally)
            };
            //驳回
            if (request.VerificationFinally == TagState.Reject.ToString())
            {
                NodeReject(request);
            }
            else
            {
                NodeVerification(request.FlowInstanceId, tag);
            }
        }
        /// <summary>
        /// 添加扭转记录
        /// </summary>
        private void AddTransHistory(FlowRuntime wfruntime)
        {
            var history = new FlowInstanceTransitionHistory
            {
                InstanceId = wfruntime.flowInstanceId,
                CreateUserId = wfruntime.UserId,
                CreateUserName = wfruntime.UserName,
                FromNodeId = wfruntime.currentNodeId,
                FromNodeName = wfruntime.currentNode.name,
                FromNodeType = wfruntime.currentNodeType,
                ToNodeId = wfruntime.nextNodeId,
                ToNodeName = wfruntime.nextNode.name,
                ToNodeType = wfruntime.nextNodeType,
                IsFinish = wfruntime.nextNodeType == 4 ? 1 : 0,
                TransitionSate = 0
            };
            flowInstanceTransitionHistoryDal.Add(history);
        }
        /// <summary>
        /// 寻找该节点执行人
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private string GetNodeMakers(FlowNode node)
        {
            string makerList = "";

            if (node.setInfo != null)
            {
                if (node.setInfo.NodeDesignate == Setinfo.ALL_USER)//所有成员
                {
                    makerList = "1";
                }
                else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_USER)//指定成员
                {
                    makerList = Utils.ArrayToString(node.setInfo.NodeDesignateData.users, makerList);
                }
                else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_ROLE)  //指定角色
                {
                    var list = relevanceDal.FindAll("Key='" + Define.ROLERESOURCE + "' and SecondId in(" + node.setInfo.NodeDesignateData.roles.ToSql(false) + ")");
                    var usersIds = list.Select(p => p.FirstId);
                    makerList = Utils.ArrayToString(usersIds, makerList);
                }
            }
            else  //如果没有设置节点信息，默认所有人都可以审核
            {
                makerList = "1";
            }
            return makerList;
        }
        /// <summary>
        /// 寻找下一步的执行人
        /// 一般用于本节点审核完成后，修改流程实例的当前执行人，可以做到通知等功能
        /// </summary>
        /// <returns></returns>
        private string GetNextMakers(FlowRuntime wfruntime)
        {
            string makerList = "";
            if (wfruntime.nextNodeId == "-1")
            {
                throw (new Exception("无法寻找到下一个节点"));
            }
            if (wfruntime.nextNodeType == 0)//如果是会签节点
            {
                List<string> _nodelist = wfruntime.FromNodeLines[wfruntime.nextNodeId].Select(u => u.to).ToList();
                string makers = "";
                foreach (string item in _nodelist)
                {
                    makers = GetNodeMakers(wfruntime.Nodes[item]);
                    if (makers == "")
                    {
                        throw (new Exception("无法寻找到会签节点的审核者,请查看流程设计是否有问题!"));
                    }
                    if (makers == "1")
                    {
                        throw (new Exception("会签节点的审核者不能为所有人,请查看流程设计是否有问题!"));
                    }
                    if (makerList != "")
                    {
                        makerList += ",";
                    }
                    makerList += makers;
                }
            }
            else
            {
                makerList = GetNodeMakers(wfruntime.nextNode);
                if (string.IsNullOrEmpty(makerList))
                {
                    throw (new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!"));
                }
            }

            return makerList;
        }
        #region 流程处理API
        /// <summary>
        /// 创建一个实例
        /// </summary>
        /// <returns></returns>
        public bool CreateInstance(AddFlowInstanceReq addFlowInstanceReq)
        {
            FlowScheme scheme = flowSchemeDal.Find(addFlowInstanceReq.SchemeId);
            if ((scheme == null) && !string.IsNullOrEmpty(addFlowInstanceReq.SchemeCode))
            {
                scheme = flowSchemeDal.FindAll("SchemeCode='" + addFlowInstanceReq.SchemeCode + "'").FirstOrDefault();
            }
            if (scheme == null)
            {
                throw new Exception("该流程模板已不存在，请重新设计流程");
            }
            addFlowInstanceReq.SchemeContent = scheme.SchemeContent;
            //DOTO:该流程模板对应的表单已不存在
            //var form = formDal.Find(scheme.FrmId);
            //if (form == null)
            //{
            //    throw new Exception("该流程模板对应的表单已不存在，请重新设计流程");
            //}
            //addFlowInstanceReq.FrmContentData = form.ContentData;
            //addFlowInstanceReq.FrmContentParse = form.ContentParse;
            //addFlowInstanceReq.FrmType = form.FrmType;
            //addFlowInstanceReq.FrmId = form.ID;
            var flowInstance = addFlowInstanceReq.MapTo<FlowInstance>();
            //创建运行实例
            var wfruntime = new FlowRuntime(flowInstance);
            #region 根据运行实例改变当前节点状态
            flowInstance.ActivityId = wfruntime.nextNodeId;
            flowInstance.ActivityType = wfruntime.GetNextNodeType();
            flowInstance.ActivityName = wfruntime.nextNode.name;
            flowInstance.PreviousId = wfruntime.currentNodeId;
            flowInstance.CreateUserId = loginInfoDal.AccountId;
            flowInstance.CreateUserName = loginInfoDal.AccountName;
            flowInstance.MakerList = (wfruntime.GetNextNodeType() != 4 ? GetNextMakers(wfruntime) : "");
            flowInstance.IsFinish = (wfruntime.GetNextNodeType() == 4 ? 1 : 0);

            Add(flowInstance);

            wfruntime.flowInstanceId = flowInstance.ID;

            if (flowInstance.FrmType == 1)
            {
                //ICustomerForm customerForm = EngineContext.Current.Resolve<ICustomerForm>();
                //customerForm.Add(flowInstance.ID, flowInstance.FrmData);
            }

            #endregion 根据运行实例改变当前节点状态

            #region 流程操作记录

            FlowInstanceOperationHistory processOperationHistoryEntity = new FlowInstanceOperationHistory
            {
                InstanceId = flowInstance.ID,
                CreateUserId = loginInfoDal.AccountId,
                CreateUserName = loginInfoDal.AccountName,
                AddTime = DateTime.Now,
                Content = "【创建】"
                          + loginInfoDal.AccountName
                          + "创建了一个流程进程【"
                          + addFlowInstanceReq.Code + "/"
                          + addFlowInstanceReq.CustomName + "】"
            };
            flowInstanceOperationHistoryDal.Add(processOperationHistoryEntity);
            #endregion 流程操作记录
            AddTransHistory(wfruntime);
            return true;
        }
        /// <summary>
        /// 驳回
        /// </summary>
        /// <returns></returns>
        public bool NodeReject(VerificationReq reqest)
        {
            FlowInstance flowInstance = Find(reqest.FlowInstanceId);
            FlowRuntime wfruntime = new FlowRuntime(flowInstance);
            string resnode = "";
            resnode = string.IsNullOrEmpty(reqest.NodeRejectStep) ? wfruntime.RejectNode() : reqest.NodeRejectStep;
            var tag = new Tag
            {
                Description = reqest.VerificationOpinion,
                Taged = (int)TagState.Reject,
                UserName = reqest.UserId,
                UserId = reqest.UserName
            };
            wfruntime.MakeTagNode(wfruntime.currentNodeId, tag);
            flowInstance.IsFinish = 4;//4表示驳回（需要申请者重新提交表单）
            if (resnode != "")
            {
                flowInstance.PreviousId = flowInstance.ActivityId;
                flowInstance.ActivityId = resnode;
                flowInstance.ActivityType = wfruntime.GetNodeType(resnode);
                flowInstance.ActivityName = wfruntime.Nodes[resnode].name;
                flowInstance.MakerList = GetNodeMakers(wfruntime.Nodes[resnode]);//当前节点可执行的人信息
                AddTransHistory(wfruntime);
            }
            Update(flowInstance);
            flowInstanceOperationHistoryDal.Add(new FlowInstanceOperationHistory
            {
                InstanceId = reqest.FlowInstanceId,
                CreateUserId = reqest.UserId,
                CreateUserName = reqest.UserName,
                AddTime = DateTime.Now,
                Content = "【"
                          + wfruntime.currentNode.name
                          + "】【" + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + "】驳回,备注："
                          + reqest.VerificationOpinion
            });

            wfruntime.NotifyThirdParty(new HttpClient(), tag);
            return true;
        }
        /// <summary>
        /// 节点审核
        /// </summary>
        /// <param name="instanceId"></param>
        /// <returns></returns>
        public bool NodeVerification(string instanceId, Tag tag)
        {
            FlowInstance flowInstance = Find(instanceId);
            FlowInstanceOperationHistory flowInstanceOperationHistory = new FlowInstanceOperationHistory
            {
                InstanceId = instanceId,
                CreateUserId = tag.UserId,
                CreateUserName = tag.UserName,
                AddTime = DateTime.Now
            };//操作记录
            FlowRuntime wfruntime = new FlowRuntime(flowInstance);

            #region 会签
            if (flowInstance.ActivityType == 0)//当前节点是会签节点
            {
                //TODO: 标记会签节点的状态，这个地方感觉怪怪的
                wfruntime.MakeTagNode(wfruntime.currentNodeId, tag);
                string canCheckId = ""; //寻找当前登录用户可审核的节点Id
                foreach (string nodeId in wfruntime.FromNodeLines[wfruntime.currentNodeId].Select(u => u.to))
                {
                    var makerList = GetNodeMakers(wfruntime.Nodes[nodeId]);
                    if (string.IsNullOrEmpty(makerList)) continue;

                    if (makerList.Split(',').Any(one => tag.UserId == one))
                    {
                        canCheckId = nodeId;
                    }
                }
                if (canCheckId == "")
                {
                    throw (new Exception("审核异常,找不到审核节点"));
                }

                flowInstanceOperationHistory.Content = "【" + wfruntime.Nodes[canCheckId].name
                                                           + "】【" + DateTime.Now.ToString("yyyy-MM-dd HH:mm")
                                                           + "】" + (tag.Taged == 1 ? "同意" : "不同意") + ",备注："
                                                           + tag.Description;

                wfruntime.MakeTagNode(canCheckId, tag); //标记审核节点状态
                string res = wfruntime.NodeConfluence(canCheckId, tag);
                if (res == TagState.No.ToString("D"))
                {
                    flowInstance.IsFinish = 3;
                }
                else if (!string.IsNullOrEmpty(res))
                {
                    flowInstance.PreviousId = flowInstance.ActivityId;
                    flowInstance.ActivityId = wfruntime.nextNodeId;
                    flowInstance.ActivityType = wfruntime.nextNodeType;
                    flowInstance.ActivityName = wfruntime.nextNode.name;
                    flowInstance.IsFinish = (wfruntime.nextNodeType == 4 ? 1 : 0);
                    flowInstance.MakerList =
                        (wfruntime.nextNodeType == 4 ? "" : GetNextMakers(wfruntime));
                    AddTransHistory(wfruntime);
                }
            }
            #endregion 会签
            #region 一般审核
            else
            {
                wfruntime.MakeTagNode(wfruntime.currentNodeId, tag);
                if (tag.Taged == (int)TagState.Ok)
                {
                    flowInstance.PreviousId = flowInstance.ActivityId;
                    flowInstance.ActivityId = wfruntime.nextNodeId;
                    flowInstance.ActivityType = wfruntime.nextNodeType;
                    flowInstance.ActivityName = wfruntime.nextNode.name;
                    flowInstance.MakerList = wfruntime.nextNodeType == 4 ? "" : GetNextMakers(wfruntime);
                    flowInstance.IsFinish = (wfruntime.nextNodeType == 4 ? 1 : 0);
                    AddTransHistory(wfruntime);
                }
                else
                {
                    flowInstance.IsFinish = 3; //表示该节点不同意
                }
                flowInstanceOperationHistory.Content = "【" + wfruntime.currentNode.name
                                                           + "】【" + DateTime.Now.ToString("yyyy-MM-dd HH:mm")
                                                           + "】" + (tag.Taged == 1 ? "同意" : "不同意") + ",备注："
                                                           + tag.Description;
            }
            #endregion 一般审核
            flowInstance.SchemeContent = JsonHelper.Instance.Serialize(wfruntime.ToSchemeObj());
            Update(flowInstance);
            flowInstanceOperationHistoryDal.Add(flowInstanceOperationHistory);
            wfruntime.NotifyThirdParty(new HttpClient(), tag);
            return true;
        }
        #endregion


    }
}


